package com.behome.system.service.impl;

import com.behome.common.annotation.DataScope;
import com.behome.common.constant.Constants;
import com.behome.common.constant.UserConstants;
import com.behome.common.core.domain.TreeSelect;
import com.behome.common.core.domain.TreeSelectByRegion;
import com.behome.common.core.domain.entity.SysRegion;
import com.behome.common.core.domain.entity.SysRole;
import com.behome.common.core.domain.entity.SysUser;
import com.behome.common.exception.ServiceException;
import com.behome.common.utils.SecurityUtils;
import com.behome.common.utils.StringUtils;
import com.behome.common.utils.spring.SpringUtils;
import com.behome.system.mapper.SysRegionMapper;
import com.behome.system.mapper.SysRoleMapper;
import com.behome.system.service.ISysRegionService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 部门管理 服务实现
 *
 * @author behome
 */
@Service
public class SysRegionServiceImpl implements ISysRegionService {

    @Resource
    private SysRegionMapper sysRegionMapper;
    @Resource
    private SysRoleMapper roleMapper;

    @Override
    @DataScope(regionAlias = "re")
    public List<SysRegion> selectRegionList(SysRegion region) {
        return sysRegionMapper.selectRegionList(region);
    }


    /**
     * 根据区域ID查询信息
     *
     * @param regionId 区域ID
     * @return 区域信息
     */
    @Override
    public SysRegion selectRegionById(String regionId) {
        return sysRegionMapper.selectById(regionId);
    }


    /**
     * 是否存在子节点
     *
     * @param regionId 区域ID
     * @return 结果
     */
    @Override
    public boolean hasChildByRegionId(String regionId) {
        int result = sysRegionMapper.hasChildByRegionId(regionId);
        return result > 0;
    }

    /**
     * 查询区域是否存在用户
     *
     * @param regionId 区域ID
     * @return 结果 true 存在 false 不存在
     */
    @Override
    public boolean checkRegionExistUser(String regionId) {
        int result = sysRegionMapper.checkRegionExistUser(regionId, Constants.SUPER_ADMIN);
        return result > 0;
    }

    /**
     * 校验区域名称是否唯一
     *
     * @param region 区域信息
     * @return 结果
     */
    @Override
    public boolean checkRegionNameUnique(SysRegion region) {
        String regionId = StringUtils.isNull(region.getRegionId()) ? "" : region.getRegionId();
        SysRegion info = sysRegionMapper.checkRegionNameUnique(region.getName(), region.getParentRegionId());
        if (StringUtils.isNotNull(info) && !info.getRegionId().equals(regionId)) {
            return !UserConstants.NOT_UNIQUE;
        }
        return !UserConstants.UNIQUE;
    }

    /**
     * 校验部门是否有数据权限
     *
     * @param regionId 区域id
     */
    @Override
    public void checkRegionDataScope(String regionId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysRegion region = new SysRegion();
            region.setRegionId(regionId);
            List<SysRegion> regions = SpringUtils.getAopProxy(this).selectRegionList(region);
            if (StringUtils.isEmpty(regions)) {
                throw new ServiceException("没有权限访问部门数据！");
            }
        }
    }

    /**
     * 新增保存区域信息
     *
     * @param region 区域信息
     * @return 结果
     */
    @Override
    public int insertRegion(SysRegion region) {
        SysRegion sysRegion = sysRegionMapper.selectById(region.getParentRegionId());
        // 如果父节点不为正常状态,则不允许新增子节点
        if (UserConstants.REGION_NORMAL.equals(String.valueOf(sysRegion.getStatus()))) {
            throw new ServiceException("上级区域停用，不允许新增");
        }
        region.setAncestors(sysRegion.getAncestors() + "," + region.getParentRegionId());
        return sysRegionMapper.insert(region);
    }

    /**
     * 修改保存区域信息
     *
     * @param region 区域信息
     * @return 结果
     */
    @Override
    public int updateRegion(SysRegion region) {
        SysRegion newParentRegion = sysRegionMapper.selectById(region.getParentRegionId());
        SysRegion oldRegion = sysRegionMapper.selectById(region.getRegionId());
        if (StringUtils.isNotNull(newParentRegion) && StringUtils.isNotNull(oldRegion)) {
            String newAncestors = newParentRegion.getAncestors() + "," + newParentRegion.getRegionId();
            String oldAncestors = oldRegion.getAncestors();
            oldRegion.setAncestors(newAncestors);
            updateRegionChildren(oldRegion.getRegionId(), newAncestors, oldAncestors);
        }
        return sysRegionMapper.updateById(region);
    }

    @Override
    public List<TreeSelectByRegion> selectRegionTreeList(SysRegion region) {
        List<SysRegion> regionList = SpringUtils.getAopProxy(this).selectRegionList(region);
        return buildRegionTreeSelect(regionList);
    }


    /**
     * 修改子元素关系
     *
     * @param regionId     被修改的部门ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    public void updateRegionChildren(String regionId, String newAncestors, String oldAncestors) {
        List<SysRegion> children = sysRegionMapper.selectChildrenRegionById(regionId);
        for (SysRegion child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
        if (!children.isEmpty()) {
            sysRegionMapper.updateRegionChildren(children);
        }
    }

    /**
     * 删除区域管理信息
     *
     * @param regionId 区域ID
     * @return 结果
     */
    @Override
    public int deleteRegionById(String regionId) {
        return sysRegionMapper.deleteById(regionId);
    }


     /**
     * 构建前端所需要树结构
     *
     * @param regions 区域列表
     * @return 树结构列表
     */
     @Override
     public List<SysRegion> buildRegionTree(List<SysRegion> regions)
    {
        List<SysRegion> returnList = new ArrayList<SysRegion>();
        List<String> tempList = Optional.ofNullable(regions).orElse(new ArrayList<>())
                .stream()
                .filter(Objects::nonNull)
                .map(SysRegion::getRegionId)
                .collect(Collectors.toList());
        assert regions != null;
        for (SysRegion region : regions)
        {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(region.getParentRegionId()))
            {
                recursionFn(regions, region);
                returnList.add(region);
            }
        }
        if (returnList.isEmpty())
        {
            returnList = regions;
        }
        return returnList;
    }
    /**
     * 构建前端所需要下拉树结构
     *
     * @param regionList 区域列表
     * @return 下拉树结构列表
     */
    @Override
    public List<TreeSelectByRegion> buildRegionTreeSelect(List<SysRegion> regionList)
    {
        List<SysRegion> regionTrees = buildRegionTree(regionList);
        return Optional.ofNullable(regionTrees).orElse(new ArrayList<>())
                .stream()
                .filter(Objects::nonNull)
                .map(TreeSelectByRegion::new)
                .collect(Collectors.toList());
    }

    /**
     * 根据角色ID查询部门树信息
     *
     * @param roleId 角色ID
     * @return 选中部门列表
     */
    @Override
    public List<String> selectRegionListByRoleId(Long roleId) {
        SysRole role = roleMapper.selectRoleById(roleId);
        return sysRegionMapper.selectRegionListByRoleId(roleId, role.isDeptCheckStrictly());
    }


    /**
     * 递归列表
     */
    private void recursionFn(List<SysRegion> list, SysRegion t)
    {
        // 得到子节点列表
        List<SysRegion> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysRegion tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysRegion> getChildList(List<SysRegion> list, SysRegion t)
    {
        List<SysRegion> tlist = new ArrayList<>();
        for (SysRegion n : list) {
            if (StringUtils.isNotNull(n.getParentRegionId()) && n.getParentRegionId().equals(t.getRegionId())) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysRegion> list, SysRegion t)
    {
        return !getChildList(list, t).isEmpty();
    }

}
